home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 09 - 1993 / 09.04 Apr 93 / Random Finder Strings / RandomFinderStrings.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-05  |  10.4 KB  |  376 lines  |  [TEXT/KAHL]

  1. /*************************************************
  2.  * RandomFinderStrings.c
  3.  *
  4.  * This INIT installs a patch on DrawString that
  5.  * will tweak strings drawn by the Finder. If
  6.  * CurApName != "/pFinder" or if the option key
  7.  * is down then a normal DrawString takes place.
  8.  * If we are in the Finder then a modified version
  9.  * of the string is drawn: the upper/lower case
  10.  * of the letters might be changed, the string
  11.  * might be flipped backwards, all the vowels
  12.  * might get accent marks, etc.
  13.  *
  14.  * You can add to the list of effects by adding
  15.  * an item to the Effects enum and the main
  16.  * switch statement in MyDrawString. If your
  17.  * effects need globals, put them in the
  18.  * PatchGlobals struct and initialize them in main.
  19.  *
  20.  * In Think C, set the Project Type to Code
  21.  * Resource, the File Type to INIT, the Creator
  22.  * to anything, the Type to INIT, the ID to
  23.  * something like 55 (55 will work but it
  24.  * doesn't have to be 55), turn Custom Header
  25.  * ON and Attrs to 20 (purgeable) and Multi
  26.  * Segment OFF.
  27.  *
  28.  * Mike Scanlin. 24 Jan 1993.
  29.  ************************************************/
  30.  
  31. /*************************************************
  32.  * defines
  33.  ************************************************/
  34. #define _DrawString         0xA884
  35.  
  36. enum Effects {
  37.     UpperCase = 0,
  38.     LowerCase,
  39.     ReverseCase,
  40.     RandomCase,
  41.     BackwardsLetters,
  42.     AccentedVowels,
  43.     NoVowels,
  44.     PigLatin,
  45.     NumEffects /* must be last */
  46. };
  47.  
  48. /* Turn these all on for maximum randomness */
  49. #define DO_CASE_CHANGES     1
  50. #define BACKWARDS_LETTERS   1
  51. #define ACCENTED_VOWELS     1
  52. #define NO_VOWELS           1
  53. #define PIG_LATIN           0
  54.  
  55. #define ALWAYS_TWEAK_STRING 1
  56.  
  57. #if ALWAYS_TWEAK_STRING && !(DO_CASE_CHANGES || \
  58.     BACKWARDS_LETTERS || ACCENTED_VOWELS || NO_VOWELS)
  59.     not!
  60.     /* Generate a compile time error if you set
  61.      * up an impossible situation. You need to
  62.      * have at least one effect enabled if
  63.      * ALWAYS_TWEAK_STRING is enabled.
  64.      */
  65. #endif
  66.  
  67.  
  68. /*************************************************
  69.  * typedefs
  70.  ************************************************/
  71. typedef pascal void (*DSProcPtr)(Str255 *theStringPtr);
  72.  
  73. typedef struct PatchGlobals {
  74.     DSProcPtr       pgOldDS;
  75. } PatchGlobals, *PatchGlobalsPtr;
  76.  
  77.  
  78. /*************************************************
  79.  * prototypes
  80.  ************************************************/
  81. void main(void);
  82. void StartPatchCode(void);
  83. pascal void MyDrawString(Str255 *theStringPtr);
  84. short abs(short n);
  85. void EndPatchCode(void);
  86.  
  87.  
  88. /*************************************************
  89.  * main
  90.  *
  91.  * Gets some memory in the system heap and
  92.  * installs the DrawString patch (as well as
  93.  * allocating and initializing the patch globals).
  94.  * This is the only routine that gets executed at
  95.  * startup time (by the INIT mechanism).
  96.  *
  97.  * The block of memory that main allocates will
  98.  * look like this when main has finished:
  99.  *
  100.  *                   +--------------------+
  101.  *                   |    PatchGlobals    |
  102.  *                   +--------------------+
  103.  *                   |  StartPatchCode()  |
  104.  *   DS trap addr -> +--------------------+
  105.  *                   |   MyDrawString()   |
  106.  *                   +--------------------+
  107.  *                   |       abs()        |
  108.  *                   +--------------------+
  109.  *                   |   EndPatchCode()   |
  110.  *                   +--------------------+
  111.  *
  112.  ************************************************/
  113. void main()
  114. {
  115.     Ptr             patchPtr;
  116.     PatchGlobalsPtr pgPtr;
  117.     long            codeSize, offset;
  118.         
  119.     /* try and get some memory in the system heap
  120.      * for code and globals */
  121.     codeSize = (long) EndPatchCode -
  122.         (long) StartPatchCode;
  123.     patchPtr = NewPtrSys(codeSize +
  124.         sizeof(PatchGlobals));
  125.     if (!patchPtr)
  126.         return; /* out of memory--abort patching */
  127.     
  128.     /* initialize the patch globals at the
  129.      * beginning of the block */
  130.     pgPtr = (PatchGlobalsPtr) patchPtr;
  131.     pgPtr->pgOldDS = (DSProcPtr)
  132.         GetTrapAddress(_DrawString);
  133.     
  134.     /* move the code into place after the globals */
  135.     BlockMove(StartPatchCode, patchPtr +
  136.         sizeof(PatchGlobals), codeSize);
  137.     
  138.     /* set the patches */
  139.     patchPtr += sizeof(PatchGlobals);
  140.     offset = (long) MyDrawString -
  141.         (long) StartPatchCode;
  142.     SetTrapAddress((long) patchPtr + offset,
  143.         _DrawString);
  144. }
  145.  
  146.  
  147. /*************************************************
  148.  * StartPatchCode
  149.  *
  150.  * Dummy proc to mark the beginning of the code
  151.  * for the patches. Make sure all of your patch
  152.  * code is between here and EndPatchCode.
  153.  ************************************************/
  154. void StartPatchCode()
  155. {
  156. }
  157.  
  158.  
  159. /*************************************************
  160.  * MyDrawString
  161.  *
  162.  * Head patch on DrawString that randomly tweaks
  163.  * the string to be drawn if the current
  164.  * application is the Finder and the Option key
  165.  * is not down.
  166.  ************************************************/
  167. pascal void MyDrawString(Str255 *theStringPtr)
  168. {
  169.     Str255          copyOfString;
  170.     EventRecord     theEvent;
  171.     PatchGlobalsPtr pgPtr;
  172.     Byte            *p, *inputPtr;
  173.     short           rand;
  174.     Byte            i, ch;
  175.         
  176.     /* if we're not in the Finder then exit */
  177.     if (*(char *) &CurApName != 6 ||
  178.       *(long *) ((Ptr) &CurApName + 1) != 'Find' ||
  179.       *(short *) ((Ptr) &CurApName + 5) != 'er' )
  180.         goto DontDoAnything;
  181.     
  182.     /* if the option key is down then exit */
  183.     OSEventAvail(0, &theEvent);
  184.     if (theEvent.modifiers & optionKey)
  185.         goto DontDoAnything;
  186.     
  187.     /* we're in the Finder so do something to a
  188.      * copy of the string (unless it's zero-length) */
  189.     if (i = *(Byte *) theStringPtr) {
  190.         p = (Byte *) ©OfString;
  191.         BlockMove(theStringPtr, p++, i + 1);
  192.  
  193. TryAgain:
  194.  
  195.         switch (abs(Random()) % NumEffects) {
  196.         
  197. #if DO_CASE_CHANGES
  198.         case UpperCase:
  199.             /* force all letters to upper case */
  200.             do {
  201.                 if (*p >= 'a' && *p <= 'z')
  202.                     *p -= 'a' - 'A';
  203.                 p++;
  204.             } while (--i);
  205.             break;
  206.             
  207.         case LowerCase:
  208.             /* force all letters to lower case */
  209.             do {
  210.                 if (*p >= 'A' && *p <= 'Z')
  211.                     *p += 'a' - 'A';
  212.                 p++;
  213.             } while (--i);
  214.             break;
  215.             
  216.         case ReverseCase:
  217.             /* flip the upper/lower case of each letter */
  218.             do {
  219.                 if (*p >= 'a' && *p <= 'z')
  220.                     *p -= 'a' - 'A';
  221.                 else if (*p >= 'A' && *p <= 'Z')
  222.                     *p += 'a' - 'A';
  223.                 p++;
  224.             } while (--i);
  225.             break;
  226.             
  227.         case RandomCase:
  228.             /* randomly set the case of each letter */
  229.             do {
  230.                 /* force to lower case */
  231.                 if (*p >= 'A' && *p <= 'Z')
  232.                     *p += 'a' - 'A';
  233.                 /* make half of them upper case */
  234.                 if (*p >= 'a' && *p <= 'z' && Random() < 0)
  235.                     *p -= 'a' - 'A';
  236.                 p++;
  237.             } while (--i);
  238.             break;
  239. #endif
  240.  
  241. #if BACKWARDS_LETTERS
  242.         case BackwardsLetters:
  243.             /* flip the string front to back */
  244.             inputPtr = (Byte *) theStringPtr + i;
  245.             do {
  246.                 *p++ = *inputPtr;
  247.                 inputPtr--;
  248.             } while (--i);
  249.             break;
  250. #endif
  251.  
  252. #if ACCENTED_VOWELS
  253.         case AccentedVowels:
  254.             /* put an accent mark over each vowel */
  255.             do {
  256.                 rand = abs(Random());
  257.                 switch (*p) {
  258.                 case 'A':
  259.                     switch (rand & (4-1)) {
  260.                     case 0: *p = 0x80; break;
  261.                     case 1: *p = 0x81; break;
  262.                     case 2: *p = 0xCB; break;
  263.                     case 3: *p = 0xCC; break;
  264.                     }
  265.                     break;
  266.                 case 'E':
  267.                     *p = 0x83;
  268.                     break;
  269.                 case 'O':
  270.                     if (Random() < 0)
  271.                         *p = 0x85;
  272.                     else
  273.                         *p = 0xCD;
  274.                     break;
  275.                 case 'U':
  276.                     *p = 0x86;
  277.                     break;
  278.                 case 'a':
  279.                     *p = 0x87 + (rand % 6);
  280.                     break;
  281.                 case 'e':
  282.                     *p = 0x8E + (rand & (4-1));
  283.                     break;
  284.                 case 'i':
  285.                     *p = 0x92 + (rand & (4-1));
  286.                     break;
  287.                 case 'o':
  288.                     *p = 0x97 + (rand % 5);
  289.                     break;
  290.                 case 'u':
  291.                     *p = 0x9C + (rand & (4-1));
  292.                     break;
  293.                 default:
  294.                     break;
  295.                 }
  296.                 p++;
  297.             } while (--i);
  298.             break;
  299. #endif
  300.  
  301. #if NO_VOWELS
  302.         case NoVowels:
  303.             /* remove all vowels */
  304.             inputPtr = (Byte *) theStringPtr + 1;
  305.             do {
  306.                 ch = *inputPtr;
  307.                 if (ch >= 'A' && ch <= 'Z')
  308.                     ch += 'a' - 'A';
  309.                 if (ch == 'a' || ch == 'e' || ch == 'i'
  310.                   || ch == 'o' || ch == 'u')
  311.                     copyOfString[0]--;
  312.                 else
  313.                     *p++ = *inputPtr;
  314.                 inputPtr++;
  315.             } while (--i);
  316.             /* make sure the string length is at least 1 */
  317.             if (copyOfString[0] == 0) {
  318.                 copyOfString[0] = 1;
  319.                 copyOfString[1] = *((Byte *) theStringPtr + 1);
  320.             }
  321.             break;
  322. #endif
  323.  
  324. #if PIG_LATIN
  325.         case PigLatin:
  326.             /* not implemented */
  327.             break;
  328. #endif
  329.  
  330.         case -1:                    
  331.         default:
  332. #if ALWAYS_TWEAK_STRING
  333.             goto TryAgain;
  334. #endif
  335.             break;
  336.         }
  337.         
  338.         theStringPtr = ©OfString;
  339.     }
  340.  
  341. DontDoAnything:
  342.     
  343.     /* find our globals */
  344.     pgPtr = (PatchGlobalsPtr) ((long) StartPatchCode -
  345.         sizeof(PatchGlobals));
  346.  
  347.     /* call the real DrawString */
  348.     (*pgPtr->pgOldDS)(theStringPtr);
  349. }
  350.  
  351.  
  352. /*************************************************
  353.  * abs
  354.  *
  355.  * Return the absolute value of n.
  356.  ************************************************/
  357. short
  358. abs(short n)
  359. {
  360.     if (n < 0)
  361.         return (-n);
  362.     return (n);
  363. }
  364.  
  365.  
  366. /*************************************************
  367.  * EndPatchCode
  368.  *
  369.  * Dummy proc to mark the end of the code for
  370.  * the patches. Make sure all of your patch code
  371.  * is between here and StartPatchCode.
  372.  ************************************************/
  373. void EndPatchCode()
  374. {
  375. }
  376.